#ifndef     __BLE_UART_H
#define     __BLE_UART_H

#include "../utils/byte_view_t.h"
#include "../utils/object.h"
#include "../utils/no_copyable.h"
#include "../rtos/message_queue.h"
#include "../utils/codec.h"
#include "../rtos/mutex.h"

namespace driver {

class BLEUart : utils::no_copyable_t {

public:
    static constexpr uint32_t MaxPkgSize = 20;
    static constexpr uint32_t RecvBuffSize = 64;
    static constexpr uint32_t WriteBuffSize = 64;
    
    BLEUart();

    void open();
    void close();

    template <typename... Ts>
    void write(uint16_t req, Ts&&... ts) {
        rtos::Mutex::Auto once(m_mutex);

        uint32_t len = utils::make_proto(m_write_buf, req, std::forward<Ts>(ts)...);
        uint32_t index = 0;
        while (index < len) {
            uint32_t n = len - index;
            if (n > MaxPkgSize) {
                n = MaxPkgSize;
            }
            write_by_dma(m_write_buf + index, n);
            index += n;
            wait_write_complete();
        }
    }

    inline osStatus_t poll(utils::byte_view_t &bw, uint32_t timeout = osWaitForever) {
        return m_mq.poll(bw, timeout);
    }

    void on_recv_idle();

private:
    static void write_by_dma(const void *buf, uint32_t len);
    static void wait_write_complete();

    rtos::MessageQueue<utils::byte_view_t, 10> m_mq;
    uint8_t m_recv_buf[RecvBuffSize];
    uint8_t m_copy_buf[RecvBuffSize];
    uint32_t m_recv_index = 0;
    uint8_t m_write_buf[WriteBuffSize];
    rtos::Mutex m_mutex;
};

inline utils::object_t<BLEUart> bleUart;

}


#endif
